#ifndef _LT_PLUGGABLE_FACTORY_H_
#define _LT_PLUGGABLE_FACTORY_H_

#include <map>
#include <string>
#include <typeinfo>
#include <list>

namespace Lotus
{
	class LOTUS_API PluggableFactory
	{
	public:    
		static PluggableFactory& getInstance();
		void* create(const char* name) const;
		void registerProduct(const char* name, void*(*constructor)(), const type_info& typeinfo);
		void getProductList(std::list<std::string>& out) const;
		template<typename T>
		const char* getProductName(const T* product) const;
	private:
		PluggableFactory();
		std::map<std::string,void*(*)()> constructors;
		std::map<const type_info*,std::string> typeinfo;
	};

	/*
	According to C++ specs:
	"The lifetime of the object referred to by the lvalue extends to the end of the program.
	Whether or not the destructor is called for the type_info object at the end of the program is unspecified."
	So it's ok to use the address of type_info object to store classes' names.
	*/
	template<typename T>
	const char* PluggableFactory::getProductName(const T* product) const
	{
		std::map<const type_info*,std::string>::const_iterator i=typeinfo.find(&typeid(*product));
		if(i==typeinfo.end())
			return NULL;
		else
			return i->second.c_str();
	}

	template<typename T>
	struct PluggableProduct
	{
		PluggableProduct(const char* name)
		{
			PluggableFactory::getInstance().registerProduct(name,constructor,typeid(T));
		}

		static void* constructor()
		{
			return new T();
		}
	};
}
#endif